﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Data.Common;
using System.Data.SqlClient;
using System.Configuration;
using System.Text;
using System.Data;
using System.Text.RegularExpressions;
using SIMCFachadaNegocio;
using SIMCObjetoNegocio;

namespace WcfServicioSeguridad
{
    public class SimcMembershipProvider : SqlMembershipProvider
    {
        //private MembershipUsuario _User;

        private FachadaSeguridad fachadaSeguridad;

        //public MembershipUsuario Usuario
        //{
        //    get { return _User; }
        //    set { _User = value; }
        //}
        string ConexAutenticacionConnectionString = ConfigurationManager.ConnectionStrings["ConexAutenticacion"].ToString();

        public SimcMembershipProvider()
        {
            fachadaSeguridad = new FachadaSeguridad();
        }

        public override bool ValidateUser(string strName, string strPassword)
        {
            try
            {
                MembershipUser user = this.GetUser(strName, true);

                if (user == null)
                {
                    return ComprobarLoginEnSQLServer(strName, strPassword);
                }

                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private bool ComprobarLoginEnSQLServer(string strName, string strPassword)
        {
            bool esValido = true;
            string connectionString = ConfigurationManager.ConnectionStrings["ConexUserSIMC"] + "User ID=" + strName + ";Password=" + strPassword;

            DbProviderFactory factory;
            string dataProvider = "System.Data.SqlClient";
            factory = DbProviderFactories.GetFactory(dataProvider);

            using (DbConnection connection = factory.CreateConnection())
            {

                connection.ConnectionString = connectionString;
                try
                {
                    connection.Open();

                }
                catch (Exception ex)
                {
                    esValido = false;
                }
                finally
                {
                    connection.Close();
                }
            }

            return esValido;
        }

        public override string ApplicationName
        {
            get
            {
                return base.ApplicationName;
            }
            set
            {
                value = base.ApplicationName;
            }
        }

        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            try
            {
                return base.ChangePassword(username, oldPassword, newPassword);
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            return base.ChangePasswordQuestionAndAnswer(username, password, newPasswordQuestion, newPasswordAnswer);
        }

        public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            int userId = fachadaSeguridad.ValidarAcceso(username, "");
            if (userId <= 0)//Si el nombre no esta siendo usado por ningun ususario interno se puede crear el ususrio externo.
            {
                return base.CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, out status);                
            }
            else
            {
                status = MembershipCreateStatus.DuplicateUserName;
                return null;
            }
        }
        public Usuario CreateUsuario(string username,
                                            string password,
                                            string email,
                                            string passwordQuestion,
                                            string passwordAnswer,
                                            bool isApproved,
                                            object providerUserKey,
                                            MembershipCreateStatus status,
                                            string telefono,
                                            string Nombre,
                                            string Apellido)
        {
            try
            {
                int userId = fachadaSeguridad.ValidarAcceso(username, "");
            }
            catch (SIMCFachadaNegocio.Excepciones.FallaLoginException)
            {

                MembershipUser user = base.CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, out status);
                if (user != null)
                {
                    Usuario usuario = new SIMCObjetoNegocio.Usuario();
                    usuario.NombreUsuario = user.UserName;
                    usuario.Telefono = telefono;
                    usuario.TempPasswordDate = DateTime.Now;
                    usuario.Nombre = Nombre;
                    usuario.Apellido = Apellido;
                    this.UpdateUsuario(usuario);

                    return usuario;
                }
                else
                    return null;

            }
            status = MembershipCreateStatus.DuplicateUserName;
            return null;
        }

        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            return base.DeleteUser(username, deleteAllRelatedData);
        }

        public override bool EnablePasswordReset
        {
            get { return base.EnablePasswordReset; }
        }

        public override bool EnablePasswordRetrieval
        {
            get { return base.EnablePasswordRetrieval; }
        }

        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            return base.FindUsersByEmail(emailToMatch, pageIndex, pageSize, out  totalRecords);
        }

        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            return base.FindUsersByName(usernameToMatch, pageIndex, pageSize, out  totalRecords);
        }

        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            return base.GetAllUsers(pageIndex, pageSize, out  totalRecords);
        }

        public override int GetNumberOfUsersOnline()
        {
            return base.GetNumberOfUsersOnline();
        }

        public override string GetPassword(string username, string answer)
        {
            return base.GetPassword(username, answer);
        }

        //public override MembershipUser GetUser(string username, bool userIsOnline)
        //{
        //    int userId = 0;
        //    MembershipUsuario user = new MembershipUsuario();
        //    try
        //    {
        //        userId = fachadaSeguridad.ValidarAcceso(username, "");
        //        if (userId > 0)//ES USUARIO INTERNO
        //        {
        //            Usuario userObject = fachadaSeguridad.BuscarUsuario(userId);
        //            user = new MembershipUsuario(base.Name, userObject.Login, userObject, userObject.email, "", "", true, false, DateTime.MinValue, userObject.UltimoLogin, userObject.UltimoLogout, DateTime.MinValue, DateTime.MinValue);
        //            user.TipoUsuario = TipoUsuario.Interno;
        //            user.TempPasswordDate = DateTime.MinValue;
        //            user.NombreCompleto = userObject.NombreCorto;
        //            user.UserId = userObject.Id;
        //            user.rol = userObject.Rol;
        //            return user;
        //        }
        //        else
        //        {
        //            return null;
        //        }
        //    }
        //    catch (SIMCFachadaNegocio.Excepciones.InactivoLoginException ex)
        //    {
        //        throw ex;
        //    }
        //    catch (SIMCFachadaNegocio.Excepciones.FallaLoginException ex)
        //    {
        //        //PUEDE SER USUARIO EXTERNO
        //        MembershipUser memUser = base.GetUser(username, userIsOnline);

        //        if (memUser != null)
        //        {
        //            user = GetUsuarioCompleto(memUser);
        //            user.TipoUsuario = TipoUsuario.Externo;
        //            user.rol = new Rol { Id = "UEX", Descripcion = "Usuario externo" };
        //            return user;
        //        }
        //        else
        //        {
        //            return null;
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        throw ex;
        //    }

        //}

        private Usuario GetUsuarioCompleto(MembershipUser memUser)
        {
            //MembershipUsuario user = MapMembership(memUser);
            Usuario usuario = new SIMCObjetoNegocio.Usuario();

            string connectionString = ConfigurationManager.ConnectionStrings["ConexAutenticacion"].ToString();

            Helper.Db db = new Helper.Db(connectionString);

            StringBuilder sql = new StringBuilder();

            sql.Append("DECLARE @UserId uniqueidentifier ");
            sql.Append("DECLARE @ApplicationId uniqueidentifier ");
            sql.Append("SELECT  @UserId = NULL ");
            sql.Append("SELECT  @UserId = u.UserId, @ApplicationId = a.ApplicationId ");
            sql.Append("FROM    dbo.aspnet_Users u, dbo.aspnet_Applications a, dbo.aspnet_Membership m ");
            sql.Append("WHERE   LoweredUserName = LOWER('" + memUser.UserName + "') AND ");
            sql.Append("u.ApplicationId = a.ApplicationId  AND ");
            sql.Append("LOWER('" + this.ApplicationName + "') = a.LoweredApplicationName AND ");
            sql.Append("u.UserId = m.UserId ");

            sql.Append(" select UserId, Telefono, TempPasswordDate, Name, LastName from  [aspnet_Users] ");
            sql.Append(" where UserId = @UserId and ApplicationId = @ApplicationId");

            DataRow row = db.GetDataRow(sql.ToString());

            usuario.Telefono = row["Telefono"].ToString();
            usuario.TempPasswordDate = Helper.DBHelper.GetDateTime(row, "TempPasswordDate");
            usuario.Nombre = row["Name"].ToString();
            usuario.Apellido = row["LastName"].ToString();
            usuario.Email = memUser.Email;
            string gu = row["UserId"].ToString();
            usuario.IdGuid = new Guid(gu);
            usuario.NombreUsuario = memUser.UserName;
            usuario.IsApproved = memUser.IsApproved;

            return usuario;
        }

        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            throw new NotImplementedException();
        }

        public override string GetUserNameByEmail(string email)
        {
            throw new NotImplementedException();
        }

        public override int MaxInvalidPasswordAttempts
        {
            get { return base.MaxInvalidPasswordAttempts; }
        }

        public override int MinRequiredNonAlphanumericCharacters
        {
            get { return base.MinRequiredNonAlphanumericCharacters; }
        }

        public override int MinRequiredPasswordLength
        {
            get { return base.MinRequiredPasswordLength; }
        }

        public override int PasswordAttemptWindow
        {
            get { return base.PasswordAttemptWindow; }
        }

        public override MembershipPasswordFormat PasswordFormat
        {
            get { return base.PasswordFormat; }
        }

        public override string PasswordStrengthRegularExpression
        {
            get { return base.PasswordStrengthRegularExpression; }
        }

        public override bool RequiresQuestionAndAnswer
        {
            get { return base.RequiresQuestionAndAnswer; }
        }

        public override bool RequiresUniqueEmail
        {
            get { return base.RequiresUniqueEmail; }
        }

        public override string ResetPassword(string username, string answer)
        {
            try
            {
                string TempPassword = base.ResetPassword(username, answer);
                Usuario user = (this.GetUsuario(username, false));

                user.TempPasswordDate = DateTime.Now;

                this.UpdateUsuario(user);

                return TempPassword;
            }
            catch (Exception ex)
            {
                throw new ArgumentException("Ha ocurrido un inconveniente: " + ex.Message);
            }
        }

        public override bool UnlockUser(string userName)
        {
            return base.UnlockUser(userName);
        }

        public override void UpdateUser(MembershipUser user)
        {
            base.UpdateUser(user);

            //this.UpdateUsuario((MembershipUsuario)user);
        }

        public void BloquearUsuario(MembershipUser usuario)
        {
            usuario.IsApproved = false;

            this.UpdateUser(usuario);
        }

        public void DesbloquearUsuario(MembershipUser usuario)
        {
            usuario.IsApproved = true;

            this.UpdateUser(usuario);
        }

        public void UpdateUsuario(Usuario usuario)
        {
            string connectionString = ConfigurationManager.ConnectionStrings["ConexAutenticacion"].ToString();

            Helper.Db db = new Helper.Db(connectionString);
            StringBuilder sql = new StringBuilder();

            sql.Append("DECLARE @UserId uniqueidentifier ");
            sql.Append("DECLARE @ApplicationId uniqueidentifier ");
            sql.Append("SELECT  @UserId = NULL ");
            sql.Append("SELECT  @UserId = u.UserId, @ApplicationId = a.ApplicationId ");
            sql.Append("FROM    dbo.aspnet_Users u, dbo.aspnet_Applications a, dbo.aspnet_Membership m ");
            sql.Append("WHERE   LoweredUserName = LOWER('" + usuario.NombreUsuario + "') AND ");
            sql.Append("u.ApplicationId = a.ApplicationId  AND ");
            sql.Append("LOWER('" + this.ApplicationName + "') = a.LoweredApplicationName AND ");
            sql.Append("u.UserId = m.UserId ");

            sql.Append(" Update [aspnet_Users] set ");
            sql.Append(" [Telefono] = '" + usuario.Telefono + "'");
            sql.Append(" ,[Name] = '" + usuario.Nombre + "'");
            sql.Append(" ,[LastName] = '" + usuario.Apellido + "'");
            if (usuario.TempPasswordDate != DateTime.MinValue)
            {
                sql.Append(", [TempPasswordDate] = '" + usuario.TempPasswordDate.ToString("yyyy/MM/dd HH:mm:ss") + "'");
            }
            else
            {
                sql.Append(", [TempPasswordDate] = NULL");
            }
            sql.Append(" where UserId = @UserId and ApplicationId = @ApplicationId");

            db.Update(sql.ToString());
        }

        //public MembershipUsuario MapMembership(MembershipUser param_member)
        //{
        //    return new MembershipUsuario(param_member.ProviderName, param_member.UserName, param_member.ProviderUserKey, param_member.Email, param_member.PasswordQuestion, param_member.Comment, param_member.IsApproved, param_member.IsLockedOut, param_member.CreationDate
        //            , param_member.LastLoginDate, param_member.LastActivityDate, param_member.LastPasswordChangedDate, param_member.LastLockoutDate);
        //}

        //public void ActualizarUsuario()
        //{
        //    _User = (MembershipUsuario)this.GetUser(_User.UserName, true);
        //}

        //public void ValidatePassword(string password, string username)
        //{
        //    if (password.Length < this.MinRequiredPasswordLength)
        //    {
        //        throw new ArgumentException("La contraseña debe tener mas de " + this.MinRequiredPasswordLength + " caracteres.");
        //    }
        //    if (password.Contains(username))
        //    {
        //        throw new ArgumentException("El nombre de usuario no debe estar incluido en la contraseña.");
        //    }
        //    if (username.Contains(password))
        //    {
        //        throw new ArgumentException("La contraseña no debe estar incluida en el nombre de usuario.");
        //    }
        //    if (username.Contains(" "))
        //    {
        //        throw new ArgumentException("El nombre de usuario no debe tener espacios.");
        //    }
        //    if (password.Contains(" "))
        //    {
        //        throw new ArgumentException("La contraseña no debe tener espacios.");
        //    }

        //    int cantConjuntos = 0;
        //    try
        //    {
        //        cantConjuntos = Convert.ToInt32(ConfigurationManager.AppSettings["CantidadConjuntosPassword"]);
        //    }
        //    catch (Exception ex)
        //    {
        //        throw new ArgumentException("Cantidad invalida de conjuntos en webConfig");
        //    }

        //    if (!this.TieneMinusculas(password) && (cantConjuntos > 0))
        //    {
        //        throw new ArgumentException("La contraseña debe tener al menos una letra minuscula.");
        //    }
        //    if (!this.TieneMayusculas(password) && (cantConjuntos > 1))
        //    {
        //        throw new ArgumentException("La contraseña debe tener al menos una letra mayuscula.");
        //    }
        //    if (!this.TieneNumeros(password) && (cantConjuntos > 2))
        //    {
        //        throw new ArgumentException("La contraseña debe tener al menos un numero.");
        //    }
        //    if (!this.TieneCaracteresEspeciales(password) && (cantConjuntos > 3))
        //    {
        //        throw new ArgumentException("La contraseña debe tener al menos un caracter especial");
        //    }
        //}

        //private bool TieneMinusculas(string strToCheck)
        //{
        //    Regex objAlphaNumericPattern = new Regex("[+a-z]");

        //    return objAlphaNumericPattern.IsMatch(strToCheck);
        //}

        //private bool TieneMayusculas(string strToCheck)
        //{
        //    Regex objAlphaNumericPattern = new Regex("[+A-Z]");

        //    return objAlphaNumericPattern.IsMatch(strToCheck);
        //}

        //private bool TieneNumeros(string strToCheck)
        //{
        //    Regex objAlphaNumericPattern = new Regex("[+0-9]");

        //    return objAlphaNumericPattern.IsMatch(strToCheck);
        //}

        //private bool TieneCaracteresEspeciales(string strToCheck)
        //{
        //    Regex objAlphaNumericPattern = new Regex("[+#$&=*]");

        //    return objAlphaNumericPattern.IsMatch(strToCheck);
        //}

        //private bool TieneCaracteresProhibidos(string strToCheck)
        //{
        //    Regex objAlphaNumericPattern = new Regex("[+#$&=*]");

        //    return objAlphaNumericPattern.IsMatch(strToCheck);
        //}

        // Inicio Lili
        public Usuario GetUsuario(string username, bool userIsOnline)
        {
            int userId = 0;
            try
            {
                userId = fachadaSeguridad.ValidarAcceso(username, "");
                if (userId > 0)//ES USUARIO INTERNO
                {
                    Usuario userObject = fachadaSeguridad.BuscarUsuario(userId);
                    //user = new MembershipUsuario(base.Name, userObject.Login, userObject, userObject.email, "", "", true, false, DateTime.MinValue, userObject.UltimoLogin, userObject.UltimoLogout, DateTime.MinValue, DateTime.MinValue);
                    userObject.TipoUsuario = TipoUsuario.Interno;
                    userObject.TempPasswordDate = DateTime.MinValue;
                    return userObject;
                }
                else
                {
                    return null;
                }
            }
            catch (SIMCFachadaNegocio.Excepciones.InactivoLoginException ex)
            {
                throw ex;
            }
            catch (SIMCFachadaNegocio.Excepciones.FallaLoginException ex)
            {
                //PUEDE SER USUARIO EXTERNO
                MembershipUser memUser = base.GetUser(username, userIsOnline);
                
                if (memUser != null)
                {
                    Usuario ususrio = GetUsuarioCompleto(memUser);
                    ususrio.TipoUsuario = TipoUsuario.Externo;
                    ususrio.Rol = new Rol { Id = "UEX", Descripcion = "Usuario externo" };
                    return ususrio;
                }
                else
                {
                    return null;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

        public List<Usuario> GetUsuarioPorLogin(string Login)
        {

            Usuario User = new Usuario();

            List<Usuario> UserList = new List<Usuario>();

            string ConnectionString = ConfigurationManager.ConnectionStrings["ConexAutenticacion"].ToString();

            Helper.Db db = new Helper.Db(ConnectionString);

            StringBuilder Sql = new StringBuilder();

            Sql.Append(" select u.[UserName], u.[Name], u.[LastName], u.[Telefono], m.[Email] from  [aspnetdb].[dbo].[aspnet_Users] u, [aspnetdb].[dbo].[aspnet_Applications] a, [aspnetdb].[dbo].[aspnet_Membership] m");
            Sql.Append(" where a.[LoweredApplicationName] = LOWER('" + this.ApplicationName + "') AND");
            Sql.Append(" u.[UserName] like '" + Login + "%' AND u.UserId = m.UserId");


            MapListaUsuario(User, UserList, db, Sql);

           //BuscarUsuariosInternos(Login, string.Empty, string.Empty, UserList);

            return UserList;
        }

        public List<Usuario> GetUsuarioPorEmail(string Email)
        {
            Usuario User = new Usuario();

            List<Usuario> UserList = new List<Usuario>();

            string ConnectionString = ConfigurationManager.ConnectionStrings["ConexAutenticacion"].ToString();

            Helper.Db db = new Helper.Db(ConnectionString);

            StringBuilder Sql = new StringBuilder();

            Sql.Append(" select [UserName], [Name], [LastName], [Telefono] from, m.Email  [aspnetdb].[dbo].[aspnet_Users] u,");
            Sql.Append(" [aspnetdb].[dbo].[aspnet_Applications] a,[aspnetdb].[dbo].[aspnet_Membership] m");
            Sql.Append(" where [LoweredApplicationName] = LOWER('" + this.ApplicationName + "') AND");
            Sql.Append(" u.[UserId] = m.[UserId] AND");
            Sql.Append(" [Email] = '" + Email + "\'");

            MapListaUsuario(User, UserList, db, Sql);
            //BuscarUsuariosInternos(string.Empty, string.Empty, Email, UserList);

            return UserList;
        }        

        public List<Usuario> GetUsuariosPorNombre(string Nombre)
        {
            Usuario User = new Usuario();

            List<Usuario> UserList = new List<Usuario>();

            string ConnectionString = ConfigurationManager.ConnectionStrings["ConexAutenticacion"].ToString();

            Helper.Db db = new Helper.Db(ConnectionString);

            StringBuilder Sql = new StringBuilder();

            Sql.Append(" select [UserName], [Name], [LastName], [Telefono], Email from  [aspnetdb].[dbo].[aspnet_Users] u, [aspnetdb].[dbo].[aspnet_Applications],[aspnetdb].[dbo].[aspnet_Membership] m");
            Sql.Append(" where [LoweredApplicationName] = LOWER('" + this.ApplicationName + "') AND u.[UserId] = m.[UserId] AND");
            Sql.Append(" [Name] like '" + Nombre + "%'");

            MapListaUsuario(User, UserList, db, Sql);

            //BuscarUsuariosInternos(string.Empty, Nombre, string.Empty, UserList);

            return UserList;
        }

        private void MapListaUsuario(Usuario User, IList<Usuario> UserList, Helper.Db db, StringBuilder Sql)
        {
            DataTable dt = db.GetDataTable(Sql.ToString());

            foreach (DataRow row in dt.Rows)
            {

               UserList.Add(MapToUsuario(row));

            }
        }

        private Usuario MapToUsuario(DataRow row)
        {
            Usuario User = new SIMCObjetoNegocio.Usuario();
            User.NombreUsuario = row["UserName"].ToString();
            User.Email = row["Email"].ToString();
            User.Apellido = row["LastName"].ToString();
            User.Nombre = row["Name"].ToString();
            User.Telefono = row["Telefono"].ToString();
            User.TipoUsuario = TipoUsuario.Externo;
            User.NombreCompleto = User.Nombre + " " + User.Apellido;
            return User;
            
        }


        // Fin Lili

        //private void BuscarUsuariosInternos(string Login, string nombre, string email, List<MembershipUsuario> UserList)
        //{
        //    IList<Usuario> usuariosInternos = fachadaSeguridad.BuscarUsuariosConRolExterno(Login, nombre, email);

        //    if (usuariosInternos != null)
        //    {
        //        foreach (Usuario user in usuariosInternos)
        //        {
        //            MembershipUsuario usuario = new MembershipUsuario(base.Name, user.Login, user, user.email, "", "", true, false, DateTime.MinValue, user.UltimoLogin, user.UltimoLogout, DateTime.MinValue, DateTime.MinValue);
        //            usuario.TipoUsuario = TipoUsuario.Interno;
        //            UserList.Add(usuario);
        //        }
        //    }
        //}
    }
}